////////////////////////////////////////////////
// DESCRIPTION:
//    Win32 Thread library
//
// Legal Notices:
//     Copyright (c) 2008, Telliam Consulting, LLC.
//     All rights reserved.
//
//     Redistribution and use in source and binary forms, with or without modification,
//     are permitted provided that the following conditions are met:
//
//     * Redistributions of source code must retain the above copyright notice,
//       this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright notice,
//       this list of conditions and the following disclaimer in the documentation
//       and/or other materials provided with the distribution.
//
//     * Neither the name of Telliam Consulting nor the names of its contributors
//       may be used to endorse or promote products derived from this software
//       without specific prior written permission.
//
// Disclaimer:
//     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
//     ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
//     WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
//     IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
//     INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
//     BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
//     DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
//     LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
//     OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
//     OF THE POSSIBILITY OF SUCH DAMAGE.  
//
#pragma once

#if defined(UNDER_CE)
    #include <NKINTR.h>
#endif

#include "Handle.h"
#include "SynchObjs.h"
#include <Loki\Functor.h>

namespace FusionWare
{
    namespace Threads
    {
        ////////////////////////////////////////////////
        // Description:
        //   Base class for thread templates
        //
        // Remarks:
        //   Using a base class for the templates prevents 
        //   duplication of core functionality in every template
        //   instance. This class essentially provides a wrapper
        //   around a WIN32 thread handle and support functions.
        //
        class Thread : public FusionWare::Win32::TWin32Handle<NULL> 
        {

        public:
            Thread()  {}      
            ~Thread() {}

            Thread(const Thread& Src) 
                : FusionWare::Win32::TWin32Handle<NULL>(Src)
            {
            }

            Thread& operator=(HANDLE h)        { FusionWare::Win32::TWin32Handle<NULL>::operator=(h); return *this;}
            Thread& operator=(const Thread& R) { FusionWare::Win32::TWin32Handle<NULL>::operator=(R); return *this;}

            ///////////////////////////////////////////////////////
            // Description: 
            //    typedef for Thread functors
            //
            // Remarks:
            //    This Functor typedef allows the thread classes
            //    to deal with free standing functions and class
            //    instance methods in a clean unified fashion.
            //
            typedef Loki::Functor<UINT32> ThreadFunction;

            DWORD Suspend();
            DWORD Resume();
            bool WaitForExit(DWORD timeout=INFINITE);
        
            bool SetPriority(int p, bool extended=false);
            int GetPriority(bool extended=false);
            DWORD GetExitCode();

            bool IsRunning();

            ///////////////////////////////////////////////////////
            // Description: 
            //    Starts the thread
            //
            // Input: 
            //    pFunc       - Function to run for the thread
            //    Priority    - Thread priority
            //    PriExt      - flag to indicate if priority is extended
            //    flags       - thread start flags
            //    StackSize - stack size for the thread
            //
            // Remarks: 
            //    PriExt is used on Windows CE systems to indicate the priority
            //    an extended one it is ignored on onon-Windows CE systems.
            //     
            // Note: 
            //     
            bool Start( ThreadFunction Func
                      , int Priority = THREAD_PRIORITY_NORMAL
                      , bool PriExt = false
                      , DWORD flags=0
                      , DWORD StackSize=0);

        protected:
            ThreadFunction ThreadFunc;
            static DWORD ThreadStub( Thread* pThread);
        };


        ////////////////////////////////////////////////
        // Description:
        //    Suspends the thread
        //
        // Returns:
        //    DWORD -  previous suspend count or 0xffffffff on error
        //
        // Remarks:
        //    Suspends the thread. See also Resume().
        //
        inline DWORD Thread::Suspend()
        {
            return SuspendThread(this->Win32Handle);
        }

        ////////////////////////////////////////////////
        // Description:
        //   Resumes a previously suspended thread
        //
        // Returns:
        //   DWORD - Suspend Count or 0xFFFFFFFF on fail 
        //
        // Remarks:
        //   Resumes a thread suspended by Suspend() and those
        //   started in the suspend state
        //
        // See Also:
        //   Suspend(), Start()
        //
        inline DWORD Thread::Resume()
        {
            return ResumeThread(this->Win32Handle);
        }

        ////////////////////////////////////////////////
        // Description:
        //    Waits for the thread function to exit.
        //
        // Input:
        //    timeout - Time, in milliseconds, to wait for
        //              the thread to exit.
        //
        // Returns:
        //    bool - true on success or false on fail
        //
        // Remarks:
        //    Waits for the thread to exit. If the thread 
        //    does not yet exist the result is *TRUE*. Otherwise
        //    the result depends on the success of the wait. If it 
        //    times out then the result is FALSE.
        //
        inline bool Thread::WaitForExit(DWORD timeout/*=INFINITE*/)
        {
            if(0==timeout || this->Win32Handle==NULL)
                return TRUE;

            return WAIT_OBJECT_0 == WaitForSingleObject(this->Win32Handle, timeout);
        }

        ////////////////////////////////////////////////
        // Description:
        //    Sets the thread priority
        //
        // Input:
        //    p        - new priority
        //    extended - Windows CE: indicates extended priority
        //               set via CeSetThreadPriority(). Ignored
        //               on non Windows CE systems.
        // Returns:
        //    TRUE if succesful FALSE if not
        //
        // Remarks:
        //    Sets the priority for a thread. If specifying the
        //    extended priorities on Windows CE and the OS implements
        //    a secured configuration then the calling process
        //    must be a trusted application to set the extended priorities.
        //
        inline bool Thread::SetPriority(int p,bool extended)
        {
        #if defined(UNDER_CE) && (_WIN32_WCE >= 300)
            if(extended)
                return 0!=CeSetThreadPriority(this->Win32Handle, p);
            else
        #endif
                return 0!=SetThreadPriority(this->Win32Handle, p);
        }

        ////////////////////////////////////////////////
        // Description:
        //    Gets the thread priority
        //
        // Input:
        //    extended - Windows CE: indicates extended priority
        //               retrieved via CeGetThreadPriority(). Ignored
        //               on non Windows CE systems.
        // Returns:
        //    Priority of the thread
        //
        // Remarks:
        //    Gets the priority for a thread. If specifying the
        //    extended priorities on Windows CE and the OS implements
        //    a secured cinfiguration then the calling process
        //    must be a trusted application to set the extended priorities.
        //
        inline int Thread::GetPriority(bool extended)
        {
            if(this->Win32Handle==NULL)
                return THREAD_PRIORITY_ERROR_RETURN;

        #if defined(UNDER_CE) && _WIN32_WCE>=300
            if(extended)
                return CeGetThreadPriority(this->Win32Handle);
            else
        #endif
                return GetThreadPriority(this->Win32Handle);
        }

        ////////////////////////////////////////////////
        // Description:
        //    Retrieves the exit code of the thread
        //
        // Returns:
        //    DWORD - exit code (return value) for the
        //            thread or STILL_ACTIVE.
        //
        // Remarks:
        //    Retrieves the threads exit code.
        //
        inline DWORD Thread::GetExitCode()
        {
            DWORD exitCode;

            GetExitCodeThread(this->Win32Handle, &exitCode);
            return exitCode;
        }

        inline bool Thread::IsRunning()
        {
            return STILL_ACTIVE == GetExitCode();
        }
 
        ////////////////////////////////////////////////
        // Description:
        //   Extends Thread to support threads that
        //   can be stopped .
        //
        // Remarks:
        //   Supports threads that loop until told to stop.
        //
        // Note:
        //   The thread method *MUST* call the GetAbortFlag
        //   in it's loop to test if it should exit the loop.
        //
        class StoppableThread: public Thread
        {
        public:
            StoppableThread();
            ~StoppableThread();

            ///////////////////////////////////////////////////////
            // Description: 
            //    typedef for Thread functors
            //
            // Input:
            //    StoppableThread - Thread handle object to use
            //                      to determine when to stop. 
            //
            // Remarks:
            //    This Functor typedef allows the thread classes
            //    to deal with free standing functions and class
            //    instance methods in a clean unified fashion.
            //
            typedef Loki::Functor<UINT32, TYPELIST_1(StoppableThread)> StoppableThreadFunction;

            bool GetAbortFlag();
            bool Stop(DWORD timeout = INFINITE);

            ///////////////////////////////////////////////////////
            // Description: 
            //    Starts the thread
            //
            // Input: 
            //    Func       - Function to run for the thread
            //    Priority    - Thread priority
            //    PriExt      - flag to indicate if priority is extended
            //    flags       - thread start flags
            //    StackSize - stack size for the thread
            //
            // Remarks: 
            //    PriExt is used on Windows CE systems to indicate the priority
            //    an extended one it is ignored on non-Windows CE systems.
            //     
            bool Start( StoppableThreadFunction Func
                      , int Priority = THREAD_PRIORITY_NORMAL
                      , bool PriExt = false
                      , DWORD flags=0
                      , DWORD StackSize=0)
            {
                return Thread::Start(Loki::BindFirst(Func, *this), Priority, PriExt, flags, StackSize);
            }


        private:
            bool Abort;
        };

        inline StoppableThread::StoppableThread()
        {
            this->Abort=FALSE;
        }

        inline StoppableThread::~StoppableThread()
        {
            Stop();
        }

        ////////////////////////////////////////////////
        // Description:
        //    Sets a flag to indicate thread should stop.
        //
        // Input:
        //    timeout - time to wiat for thread to exit 
        //              0 = none, INFINITE = forever
        //
        // Returns:
        //    bool - true if succesful FALSE if not.
        //
        // Remarks:
        //    Sets the abort flag for a thread. Threads
        //    that run continuously should test the IsAborting
        //    property to see if they should stop running. 
        //    
        //    If the Thread does not test for the abort
        //    flag this will have no effect. So Care should be taken
        //    when using the Wait flag.
        //
        inline bool StoppableThread::Stop(DWORD timeout)
        {
            this->Abort = true;
            Resume();
            return WaitForExit(timeout);
        }

        ////////////////////////////////////////////////
        // Description:
        //    Retrieves the Abort flag
        //
        // Returns:
        //    Current state of the abort flag
        //
        // Remarks:
        //    Retrieves the current state of the abort flag.
        //    This method is also available through the 
        //    IsAborting property.
        //
        inline bool StoppableThread::GetAbortFlag()
        {
            return this->Abort;
        }

        #if defined(UNDER_CE) && defined(WINCEOEM)
        ////////////////////////////////////////////////
        // Description:
        //    Base class for implementing Windows CE 
        //    Interrupt Service Threads (IST).
        //
        // Remarks:
        //    Extends Thread with standard
        //    IST support functionality.
        //
        class IntSvcThread : protected StoppableThread
        {
            Event hIntEvent;
            int SysIntr;

        public:
            IntSvcThread();
            ~IntSvcThread();

            ///////////////////////////////////////////////////////
            // Description: 
            //    typedef for Thread functors
            //
            // Input:
            //    StoppableThread - Thread handle object to use
            //                      to determine when to stop. 
            //
            // Remarks:
            //    This Functor typedef allows the thread classes
            //    to deal with free standing functions and class
            //    instance methods in a clean unified fashion.
            //
            typedef Loki::Functor<UINT32, TYPELIST_1(IntSvcThread)> IntSvcThreadFunction;

            
            bool Init(int SysIntr, void *dat=NULL, DWORD cbDat=0); // create event and hook into OS
            void SetInterruptEvent();

            ///////////////////////////////////////////////////////
            // Description: 
            //    Starts the thread
            //
            // Input: 
            //    pFunc       - Function to run for the thread
            //    Priority    - Thread priority
            //    PriExt      - flag to indicate if priority is extended
            //    flags       - thread start flags
            //    StackSize - stack size for the thread
            //
            // Remarks: 
            //    PriExt is used on Windows CE systems to indicate the priority
            //    an extended one it is ignored on non-Windows CE systems.
            //     
            // Implementation Note: 
            //    Hides the use of Loki::BindFirst to get a valid Thread::ThreadFunction
            //
            bool Start( IntSvcThreadFunction Func
                      , int Priority
                      , bool PriExt=true
                      , DWORD flags=0
                      , DWORD StackSize=0)
            {
                return Thread::Start(Loki::BindFirst(Func,*this), Priority, PriExt, flags, StackSize);
            }

            ////////////////////////////////////////////////
            // Description:
            //    Stops the IST in preperation for device shutdown
            //
            // Returns:
            //    bool - TRUE if the thread was stopped FALSE if not
            //
            // Remarks:
            //    Overloads base class implementation of Stop 
            //    to handle special cases of IST threads where
            //    the interrupt event must be set to pop the IST
            //    out of it's infinite wait.
            //
            bool IntSvcThread::Stop(DWORD timeout=INFINITE);

        
            void InterruptDone();

            // enum for values returned by WaitForInterrupt
            enum ISTWait
            {
                IST_ABORT,     // IST Loop (and thread) should exit
                IST_INTERRUPT, // Got an Interupt event
                IST_TIMEOUT,   // Wait timed out
            };

            ISTWait IntSvcThread::WaitForInterrupt(UINT32 TimeOut = INFINITE);
        };

        ///////////////////////////////////////////////////////
        // Description: 
        //    typedef for Thread functors
        //
        // Input:
        //    StoppableThread - Thread handle object to use
        //                      to determine when to stop. 
        //
        // Remarks:
        //    This Functor typedef allows the thread classes
        //    to deal with free standing functions and class
        //    instance methods in a clean unified fashion.
        //    This exists outside the IntSvcThread class
        //    definition to minimize typeing and keep code
        //    lines smaller and more clear.
        //
        typedef IntSvcThread::IntSvcThreadFunction IstHandler;

        inline IntSvcThread::IntSvcThread()
        {
            SysIntr = SYSINTR_NOP;
        }

        ////////////////////////////////////////////////
        // Description:
        //   Destroys a thread object
        //
        // Remarks:
        //    Attempts to stop the thread if it is running.
        //
        // Design Notes:
        //
        inline IntSvcThread::~IntSvcThread()
        {
            Stop();
        }

        ////////////////////////////////////////////////
        // Description:
        //   Creates the IST event and registers it with the system
        //
        // Input:
        //   SysIntr - Logical ID of the thread. 
        //   dat     - data to provide to the ISR [default= NULL]
        //   cbDat   - BYTE count of data         [default =0]
        //
        // Returns:
        //    true if succesfull false if not
        //
        // Remarks:
        //    Creates the interrupt event and registers it with the
        //    OS for the SysIntr specified.
        //
        inline bool IntSvcThread::Init(int SysIntr,void *dat,DWORD cbDat)
        {
            this->SysIntr = SysIntr; 
            this->hIntEvent.Create();
            if(!this->hIntEvent)
                return false;
       
            return 0!=InterruptInitialize(this->SysIntr, this->hIntEvent.GetHandle(), dat, cbDat);
        }

        ////////////////////////////////////////////////
        // Description:
        //    Sets the interrupt event for the ISTs logical ID
        //
        // Remarks:
        //    This is used in power handlers to to "fake"
        //    an interrupt event to the thread so it will pop out
        //    of it's wait to handle any power on issues.
        // 
        //    This method should only be called in the power handler
        //    of a device driver.
        // 
        inline void IntSvcThread::SetInterruptEvent()
        {
            ::SetInterruptEvent(this->SysIntr);
        }

        ////////////////////////////////////////////////
        // Description:
        //    Indicates to the OS the interrupt was handled
        //
        // Remarks:
        //    Should only be called from within the IST to
        //    to indicate to the OS the interrupt is handled
        //    and the IST is ready for another one. The kernel
        //    will then re-enable the interrupt.
        //
        inline void IntSvcThread::InterruptDone()
        {
            ::InterruptDone(this->SysIntr);
        }

        #endif //UNDER_CE
    }
}